#include <unistd.h>
#include <string.h>
#include <iostream>
#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <pwd.h>
#include <grp.h>
#include <time.h>
#include <string>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>

using namespace std;
#define FILE_PATH_MAX_SIZE 255
<<<<<<< HEAD
#define TARGET_PATH "/home/ubuntu/Desktop/op/os-experiments/test4/"
=======
#define TARGET_PATH "/home/chenliangwei/target"
>>>>>>> test4 readme update

int MyLs(char *cur_path, char *target_path);

int FileType(const char filepath[]){
	struct stat info;
	int r = stat(filepath, &info);
	if (r == 0){
		if (S_ISREG(info.st_mode))
			return 1;
		else if (S_ISDIR(info.st_mode))
			return 2;
		else
			return -1;
	}
	else{
		cout << "[Error] FileType generates error\n";
	}
}

void ProcessCopy(const char src_path[], const char target_path[]){
	pid_t pid = fork();
	if (pid < 0){
		cout << "[Error] Failed to fork!\n";
	}
	else if (pid == 0){
		//run the executable file
		if (execl("./cp", "./cp", src_path, target_path, NULL) < 0)
			cout << "[Error] ProcessCopy execl error!\n";
	}
	else{
		int status;
		if (wait(&status) == -1)
			cout << "[Error] failed to wait!\n";
	}
}

void ProcessSelf(const char cur_path[], const char target_path[]){
	pid_t pid = fork();
	if (pid < 0){
		cout << "[Error] failed to fork!" << endl;
	}
	else if (pid == 0){
		char *s_path = new char[FILE_PATH_MAX_SIZE];
		char *t_path = new char[FILE_PATH_MAX_SIZE];
		strcpy(s_path, cur_path);
		strcpy(t_path, target_path);
		MyLs(s_path, t_path);
		delete[] s_path;
		delete[] t_path;
		s_path = NULL;
		t_path = NULL;
	}
	else{
		int status;
		if (wait(&status) == -1)
<<<<<<< HEAD
			cout << "[Error] failed to wait!" << endl;
=======
			cout << "[Error] failed to wait!\n";
>>>>>>> test4 readme update
	}
}

int MyLs(char *cur_path, char *target_path){
	char *path;
	char *src_path = new char[FILE_PATH_MAX_SIZE];
	char *new_target_path = new char[FILE_PATH_MAX_SIZE];

	if (cur_path != NULL){
		path = cur_path;
	}
	else{
		path = new char[FILE_PATH_MAX_SIZE];
		if (getcwd(path, FILE_PATH_MAX_SIZE) == NULL){
<<<<<<< HEAD
			cout << "[Error] getcwd fail!";
=======
			cout << "[Error] getcwd fail!\n";
>>>>>>> test4 readme update
			return 0;
		}
	}

	if (target_path == NULL){
		target_path = TARGET_PATH;
	}
    
    // Open current directory.
	DIR *currentdir = opendir(path); 
    
	if (currentdir != NULL){
		struct dirent *currentdp;
		while ((currentdp = readdir(currentdir)) != NULL){
			if (currentdp->d_name[0] != '.'){
				//Get the file path
				strcpy(src_path, path);
				strcat(src_path, "/");
				strcat(src_path, currentdp->d_name);

				//file or directiory
				int filetype = FileType(src_path);
				if (filetype == 1){
					//Copy with the process
					ProcessCopy(src_path, target_path);
				}
				else if (filetype == 2){
					strcpy(new_target_path, target_path);
					strcat(new_target_path, "/");
					strcat(new_target_path, currentdp->d_name);
					if (mkdir(new_target_path, S_IRWXU) == -1){
<<<<<<< HEAD
						cout << "[Error] mkdir failed!" << endl;
=======
						cout << "[Error] mkdir failed!\n";
>>>>>>> test4 readme update
						return 0;
					}
					ProcessSelf(src_path, new_target_path);
				}
				//ignore non regular files
			}
		}
		closedir(currentdir);
	}
	else{
		cout << "[Error] Open failed!" << endl;
	}

	if (cur_path == NULL){
		delete[] path;
		path = NULL;
	}

	delete[] src_path;
	delete[] new_target_path;
	src_path = NULL;
	new_target_path = NULL;
}

int main(int argc, char *argv[]){
	if (argc == 1){
		MyLs(NULL, NULL);
	}
	else if (argc == 2){
		MyLs(argv[1], NULL);
	}

	else{
		cout << "[Error] the argc is more than 1\n";
	}

	return 0;
}